﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFTools.Controls
{
    /// <summary>
    /// Represents a spinner control.
    /// </summary>
    [TemplatePart(Name = "PART_UP", Type = typeof(RepeatButton))]
    [TemplatePart(Name = "PART_DOWN", Type = typeof(RepeatButton))]
    public class SpinBox : TextBox
    {
        /// <summary>
        /// 内容框
        /// </summary>
        /// <summary>
        /// The down button.
        /// </summary>
        private RepeatButton downbutton;

        /// <summary>
        /// The up button.
        /// </summary>
        private RepeatButton upbutton;

        /// <summary>
        /// The part down.
        /// </summary>
        private const string PartDown = "PART_DOWN";

        /// <summary>
        /// The part up.
        /// </summary>
        private const string PartUp = "PART_UP";



        static SpinBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SpinBox), new FrameworkPropertyMetadata(typeof(SpinBox)));
        }
        
       
        /// <summary>
        /// Gets or sets the culture used when parsing the LargeChange/SmallChange properties.
        /// </summary>
        /// <value>The culture.</value>
        public CultureInfo Culture
        {
            get { return (CultureInfo)GetValue(CultureProperty); }
            set { SetValue(CultureProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="Culture"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty CultureProperty =
            DependencyProperty.Register("Culture", typeof(CultureInfo), typeof(SpinBox), new PropertyMetadata(null));

        /// <summary>
        /// Identifies the <see cref="DownButtonGeometry"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty DownButtonGeometryProperty =
            DependencyProperty.Register(
                "DownButtonGeometry", typeof(Geometry), typeof(SpinBox), new PropertyMetadata(null));

        /// <summary>
        /// Identifies the <see cref="LargeChange"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty LargeChangeProperty = DependencyProperty.Register(
            "LargeChange", typeof(int), typeof(SpinBox), new PropertyMetadata(10));

        /// <summary>
        /// Identifies the <see cref="Maximum"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
            "Maximum", typeof(int), typeof(SpinBox), new PropertyMetadata(int.MaxValue));

        /// <summary>
        /// Identifies the <see cref="Minimum"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
            "Minimum", typeof(int), typeof(SpinBox), new PropertyMetadata(int.MinValue));

        /// <summary>
        /// Identifies the <see cref="RepeatInterval"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty RepeatIntervalProperty = DependencyProperty.Register(
            "RepeatInterval", typeof(int), typeof(SpinBox), new PropertyMetadata(50));

        /// <summary>
        /// Identifies the <see cref="SmallChange"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty SmallChangeProperty = DependencyProperty.Register(
            "SmallChange", typeof(int), typeof(SpinBox), new PropertyMetadata(1));

        /// <summary>
        /// Identifies the <see cref="SpinButtonWidth"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty SpinButtonWidthProperty =
            DependencyProperty.Register(
                "SpinButtonWidth", typeof(GridLength), typeof(SpinBox), new PropertyMetadata(new GridLength(14)));

        /// <summary>
        /// Identifies the <see cref="UpButtonGeometry"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty UpButtonGeometryProperty =
            DependencyProperty.Register(
                "UpButtonGeometry", typeof(Geometry), typeof(SpinBox), new PropertyMetadata(null));

        /// <summary>
        /// Identifies the <see cref="Value"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
            "Value",typeof(int),typeof(SpinBox),new PropertyMetadata(0));




        /// <summary>
        /// Gets or sets down button geometry.
        /// </summary>
        /// <value>Down button geometry.</value>
        public Geometry DownButtonGeometry
        {
            get
            {
                return (Geometry)this.GetValue(DownButtonGeometryProperty);
            }

            set
            {
                this.SetValue(DownButtonGeometryProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the large change.
        /// </summary>
        /// <value>The large change.</value>
        public int LargeChange
        {
            get
            {
                return (int)this.GetValue(LargeChangeProperty);
            }

            set
            {
                this.SetValue(LargeChangeProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the maximum.
        /// </summary>
        /// <value>The maximum.</value>
        public int Maximum
        {
            get
            {
                return (int)this.GetValue(MaximumProperty);
            }

            set
            {
                this.SetValue(MaximumProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the minimum.
        /// </summary>
        /// <value>The minimum.</value>
        public int Minimum
        {
            get
            {
                return (int)this.GetValue(MinimumProperty);
            }

            set
            {
                this.SetValue(MinimumProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the repeat SmallChange (milliseconds). 
        /// </summary>
        /// <value>The repeat SmallChange.</value>
        public int RepeatInterval
        {
            get
            {
                return (int)this.GetValue(RepeatIntervalProperty);
            }

            set
            {
                this.SetValue(RepeatIntervalProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the SmallChange. 增加量
        /// </summary>
        /// <value>The SmallChange.</value>
        public int SmallChange
        {
            get
            {
                return (int)this.GetValue(SmallChangeProperty);
            }

            set
            {
                this.SetValue(SmallChangeProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the width of the spin buttons.
        /// </summary>
        /// <value>The width of the spin button.</value>
        public GridLength SpinButtonWidth
        {
            get
            {
                return (GridLength)this.GetValue(SpinButtonWidthProperty);
            }

            set
            {
                this.SetValue(SpinButtonWidthProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets up button geometry.
        /// </summary>
        /// <value>Up button geometry.</value>
        public Geometry UpButtonGeometry
        {
            get
            {
                return (Geometry)this.GetValue(UpButtonGeometryProperty);
            }

            set
            {
                this.SetValue(UpButtonGeometryProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>The value.</value>
        public int Value
        {
            get
            {
                int val = (int)this.GetValue(ValueProperty);
                return val;
            }

            set
            {
                ValueToString();//同时设置Text
                this.SetValue(ValueProperty, value);
            }
        }

        /// <summary>
        /// When overridden in a derived class, is invoked whenever application code or internal processes call <see
        /// cref="M:System.Windows.FrameworkElement.ApplyTemplate" />.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.upbutton = this.GetTemplateChild(PartUp) as RepeatButton;
            this.downbutton = this.GetTemplateChild(PartDown) as RepeatButton;

            if (this.upbutton != null)
            {
                this.upbutton.Click += this.UpbuttonClick;
            }

            if (this.downbutton != null)
            {
                this.downbutton.Click += this.DownbuttonClick;
            }

            ValueToString();   ////将Value刷新为Text

        }
        /// <summary>
        /// 从值到字符串
        /// </summary>
        private void ValueToString()
        {
            int val = (int)this.GetValue(ValueProperty);
            this.Text = val.ToString();
            //光标设置到最后
            this.SelectionStart = this.Text.Length;
        }

        /// <summary>
        /// Invoked when an unhandled <see cref="E:System.Windows.Input.Mouse.MouseWheel" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.Windows.Input.MouseWheelEventArgs" /> that contains the event data.</param>
        protected override void OnMouseWheel(MouseWheelEventArgs e)
        {
            base.OnMouseWheel(e);
            bool ctrl = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
            bool shift = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
            if (e.Delta > 0)
            {
                this.ChangeValue(1, ctrl || shift);
            }
            else
            {
                this.ChangeValue(-1, ctrl || shift);
            }

            e.Handled = true;
        }

        /// <summary>
        /// Invoked when an unhandled <see cref="E:System.Windows.Input.Keyboard.PreviewKeyDown" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.Windows.Input.KeyEventArgs" /> that contains the event data.</param>
        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            base.OnPreviewKeyDown(e);
            switch (e.Key)
            {
                case Key.Up:
                    this.ChangeValue(1, false);
                    e.Handled = true;
                    break;
                case Key.Down:
                    this.ChangeValue(-1, false);
                    e.Handled = true;
                    break;
                case Key.PageUp:
                    this.ChangeValue(1, true);
                    e.Handled = true;
                    break;
                case Key.PageDown:
                    this.ChangeValue(-1, true);
                    e.Handled = true;
                    break;
            }
        }

       

       

        /// <summary>
        /// Changes the value.
        /// </summary>
        /// <param name="sign">The sign of the change.</param>
        /// <param name="isLargeChange">The is Large Change.</param>
        private void ChangeValue(int sign, bool isLargeChange)
        {
            int intChange = isLargeChange ? this.LargeChange : this.SmallChange;


            int currentValue = (int)this.Value;
            var newValue = sign > 0 ? currentValue + intChange : currentValue - intChange;
          
            if(newValue > this.Maximum)
            {
                newValue = this.Maximum;
            }

            if(newValue<this.Minimum)
            {
                newValue = this.Minimum;
            }

            this.Value = newValue;


            return;

        }

        

       

        /// <summary>
        /// Handles down button clicks.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs" /> instance containing the event data.</param>
        private void DownbuttonClick(object sender, RoutedEventArgs e)
        {
            bool ctrl = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
            this.ChangeValue(-1, ctrl);
        }

        /// <summary>
        /// Check if an object is of a numeric type.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>
        /// True if the value is of a numeric type.
        /// </returns>
        private bool IsNumeric(object value)
        {
            if (value is double || value is int || value is uint || value is long || value is ulong || value is short
                || value is ushort || value is byte || value is sbyte || value is float || value is decimal)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Handles up button clicks.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs" /> instance containing the event data.</param>
        private void UpbuttonClick(object sender, RoutedEventArgs e)
        {
            bool ctrl = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
            this.ChangeValue(1, ctrl);
        }




        public static readonly DependencyProperty CornerRadiusProperty =
              DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(SpinBox), new PropertyMetadata(new CornerRadius(0)));
        /// <summary>
        /// 圆角大小,左上，右上，右下，左下
        /// </summary>
        public CornerRadius CornerRadius
        {
            get { return (CornerRadius)GetValue(CornerRadiusProperty); }
            set { SetValue(CornerRadiusProperty, value); }
        }

        public string WaterMark
        {
            get { return (string)GetValue(WaterMarkProperty); }
            set { SetValue(WaterMarkProperty, value); }
        }



        /// <summary>
        /// 水印内容 
        /// </summary>
        public static readonly DependencyProperty WaterMarkProperty =
            DependencyProperty.Register("WaterMark", typeof(string), typeof(SpinBox), new PropertyMetadata(""));


        public string Label
        {
            get { return (string)GetValue(LabelProperty); }
            set { SetValue(LabelProperty, value); }
        }

        /// <summary>
        /// Label标签的内容
        /// </summary>
        public static readonly DependencyProperty LabelProperty =
            DependencyProperty.Register("Label", typeof(string), typeof(SpinBox), new PropertyMetadata(""));

        public int LabelWidth
        {
            get { return (int)GetValue(LabelWidthProperty); }
            set { SetValue(LabelWidthProperty, value); }
        }

        /// <summary>
        /// Label标签的宽度
        /// </summary>
        public static readonly DependencyProperty LabelWidthProperty =
            DependencyProperty.Register("LabelWidth", typeof(int), typeof(SpinBox), new PropertyMetadata(60));
        /// <summary>
        /// Text内容改变时
        /// </summary>
        /// <param name="e"></param>
        protected override void OnTextChanged(TextChangedEventArgs e)
        {

            string text = this.Text;

            int newValue = 0;
            //转换成功 修改value的值
            if(int.TryParse(text,out newValue))
            {
                if (newValue > this.Maximum)
                {
                    newValue = this.Maximum;
                }

                if (newValue < this.Minimum)
                {
                    newValue = this.Minimum;
                }

                this.SetValue(ValueProperty, newValue);
            }
        }

        /// <summary>
        /// 按下前 判断智能输入0~9
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreviewTextInput(TextCompositionEventArgs e)
        {
            base.OnPreviewTextInput(e);
            Regex re = new Regex("[^0-9-]+$");
            e.Handled = re.IsMatch(e.Text);
        }
        
    }


}
